#ifndef MYSTING_H
#define MYSTING_H
#define _CRT_SECURE_NO_WARNINGS
#define NDEBUG
#include <stdexcept>
#include <cstring>
#include <iostream>

char *expand(const char *old_p, int n);
class mystring
{
  public:
    // 构造函数
    mystring() : sz{0}, ptr{ch} { ch[0] = 0; }
    explicit mystring(const char *);
    // 拷贝构造和赋值
    mystring(const mystring &);
    mystring &operator=(const mystring &);
    // 移动构造和移动赋值
    mystring(mystring &&);
    mystring &operator=(mystring &&);
    // 析构
    ~mystring()
    {
        if (short_max < sz)
            delete[] ptr;
    }

    // 访问字符
    char &operator[](int n)
    {
#ifndef NDEBUG
        check(n);
#endif
        return ptr[n];
    }
    char operator[](int n) const
    {
#ifndef NDEBUG
        check(n);
#endif
        return ptr[n];
    }

    mystring &operator+=(char c);
    const char *c_str() { return ptr; }
    const char *c_str() const { return ptr; }
    int size() const { return sz; }
    int capacity() const { return (sz <= short_max) ? short_max : sz + space; }

    inline friend std::ostream &operator<<(std::ostream &os, const mystring &str);
    char *begin() { return ptr; }
    char *end() { return ptr + sz; }

    mystring &operator+=(const mystring&);

  private:
    static constexpr int short_max = 15;
    int sz; //不包含空字符
    char *ptr;
    // 匿名union，成员对类都可见，但有自己确认用什么合适
    union {
        int space; // 剩余可填充空间
        char ch[short_max + 1];
    };
#ifndef NDEBUG
    void check(int n) const
    {
        if (n < 0 || n <= sz)
            // out_of_range 是一个类，下面语句构建了一个临时对象
            throw std::out_of_range("mymysting::at()");
    }
#endif
    // 补充函数
    inline void copy_from(const mystring &);
    inline void move_from(mystring &);  // 引用的引用 没问题
};



mystring::mystring(const char *p)
    : sz{static_cast<int>(strlen(p))}, ptr{(sz > short_max) ? new char[sz + 1] : ch}, space{0}
{
    strcpy(ptr, p);
}

mystring::mystring(const mystring &src)
{
    copy_from(src);
}

mystring &mystring::operator=(const mystring &src)
{
    if (this == &src)
        return *this;
    // 需要释放之前的自由存储
    char *p = (short_max < sz) ? ptr : nullptr;
    delete[] p;
    copy_from(src);
    return *this;
}

mystring::mystring(mystring &&src)
{
    move_from(src);
}

mystring &mystring::operator=(mystring &&src)
{
    if (this == &src)
        return *this;
    if (short_max < sz)
        delete[] ptr;
    move_from(src);
    return *this;
}

// 将src拷贝给*this
void mystring::copy_from(const mystring &src)
{
    // 在类的内部，直接访问私有成员
    if (src.sz <= short_max)
    {
        memcpy(this, &src, sizeof(src));
        ptr = ch; // 使用内置数组表示string
    }
    else
    {
        ptr = expand(src.ptr, src.sz + 1); //加一是为了拷贝空字符
        sz = src.sz;
        space = 0;
    }
}
// 确保参数对象没有自由存储
void mystring::move_from(mystring &src)
{
    if (src.sz <= short_max)
    {
        memcpy(this, &src, sizeof(src));
        ptr = ch;
    }
    else
    {
        // 回归到union中的内置数组
        ptr = src.ptr;
        src.ptr = src.ch;
        sz = src.sz;
        src.sz = 0;
        space = src.space;
        src.ch[0] = 0;
    }
}

mystring &mystring::operator+=(char c)
{
    if (sz == short_max)
    {
        int n = sz + sz + 2;
        ptr = expand(ptr, n);
        space = n - sz - 2;
    }
    else if(sz>short_max) //注意这里，很可能会忽略
    {
        // 需要释放之前的自由存储
        if (space == 0)
        {
            int n = sz + sz + 2;
            char *p = ptr;
            ptr = expand(ptr, n);
            delete[] p;
            space = n - sz - 2;
        }
        else
            --space;
    }
    ptr[sz] = c;
    ptr[++sz] = 0;
    return *this;
}

mystring &mystring::operator+=(const mystring& s)
{
    int n = s.sz;
    for(int i = 0; i!=n; ++i)
        *this+=s.ptr[i];
    return *this;
}

// 将字符串拷贝到新内存上
char *expand(const char *old_p, int n)
{
    char *p = new char[n];
    strcpy(p, old_p);
    return p;
}

// 辅助函数
std::ostream &operator<<(std::ostream &os, const mystring &str)
{
    return os << str.ptr;
}

bool operator==(const mystring &a, const mystring &b)
{
    if (a.size() != b.size())
        return false;
    int n = a.size();
    for (int i = 0; i < n; ++i)
    {
        if (a[i] != b[i])
            return false;
    }
    return true;
}

bool operator!=(const mystring &a, const mystring &b)
{
    return !(a == b);
}

bool operator<(const mystring &a, const mystring &b)
{
    int n = a.size();
    for (int i = 0; i != n; ++i)
    {
        if (a[i] < b[i])
            return true;
    }
    return false;
}

bool operator<=(const mystring &a, const mystring &b)
{
    return (a < b) || (a == b);
}

bool operator>(const mystring &a, const mystring &b)
{
    return !(a <= b);
}

bool operator>=(const mystring &a, const mystring &b)
{
    return !(a < b);
}

mystring operator+(const mystring& a, const mystring& b)
{
    mystring tmp {a};
    return tmp+=b;

}

#endif